# Flutter 紅包雨

最近公司要做紅包雨的效果,同事在網上找到個示範 (opens new window),記錄一下學習Animation的過程。

效果圖:

2020-05-21 21.07.01
class Homer extends StatelessWidget {
  
  Widget build(BuildContext context) {
    return Scaffold(
      body: View(
        numberOfItems: 100,
      ),
    );
  }
}

class Item {
  static final random = Random();
  double _size;
  Color _color;

  Alignment _alignment;

  Item() {
    _color = Color.fromARGB(random.nextInt(255), random.nextInt(255),
        random.nextInt(255), random.nextInt(255));
    _alignment =
        Alignment(random.nextDouble() * 2 - 1, random.nextDouble() * 2 - 1);
    _size = random.nextDouble() * 40 + 1;
  }
}

class View extends StatefulWidget {
  final int numberOfItems;

  const View({Key key, this.numberOfItems}) : super(key: key);

  
  _ViewState createState() => _ViewState();
}

class _ViewState extends State<View> with SingleTickerProviderStateMixin {
  var items = <Item>[];
  var started = false;

  AnimationController animationController;

  
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: <Widget>[
            Scaffold(
              appBar: AppBar(
                title: Text("Emoji Example Rain"),
              ),
              body: Center(
                child: RaisedButton(
                  child: Text("Start Dropping"),
                  onPressed: makeItems,
                ),
              ),
            ),
            ...buildItems()
          ],
        ),
      ),
    );
  }

  List<Widget> buildItems() {
    return items.map((item) {
      var tween = Tween<Offset>(
              begin: Offset(0, Random().nextDouble() * -1 - 1),
              end: Offset(Random().nextDouble() * 0.5, 2))
          .chain(CurveTween(curve: Curves.linear));
      return SlideTransition(
        position: animationController.drive(tween),
        child: AnimatedAlign(
          alignment: item._alignment,
          duration: Duration(seconds: 10),
          child: AnimatedContainer(
            duration: Duration(seconds: 10),
            width: item._size,
            height: item._size,
            decoration:
                BoxDecoration(color: item._color, shape: BoxShape.circle),
          ),
        ),
      );
    }).toList();
  }

  
  void initState() {
    super.initState();
    animationController =
        AnimationController(vsync: this, duration: Duration(seconds: 10));
  }

  void makeItems() {
    setState(() {
      items.clear();
      for (int i = 0; i < widget.numberOfItems; i++) {
        items.add(Item());
      }
    });
    animationController.reset();
    animationController.forward();
  }
}

因為在這個示範中沒有動態改變item._alignmentitem._size, AnimatedContainerAnimatedAlign可以使用ContainerAlign,

return SlideTransition(
  position: animationController.drive(tween),
  child: Align( //changed
    alignment: item._alignment,
    child: Container( //changed
      width: item._size,
      height: item._size,
      decoration:
      BoxDecoration(color: item._color, shape: BoxShape.circle),
    ),
  ),
);

嘗試不要SlideTransition,看看每個item的alignment位置

return Align(
        alignment: item._alignment,
        child: Container(
          width: 50, // changed, 統一尺寸
          height: 50, // changed
          decoration:
              BoxDecoration(color: item._color, shape: BoxShape.circle),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(item._alignment.x.toString(), style: TextStyle(fontSize: 5)),
              Text(item._alignment.y.toString(), style: TextStyle(fontSize: 5)),
            ],
          ),
        ),
      );

可見,每個item 一開始已經分配在全屏不同的位置(alignment)

image-20200521232710942

做個小實驗,設定item的位置時(0,0) , 並由(0,0) 移動到(1,0)

var tween = Tween<Offset>(begin: Offset(0, 0), end: Offset(1, 0)).chain(
  CurveTween(curve: Curves.linear),
);

return SlideTransition(
  position: animationController.drive(tween),
  child: Align(
    alignment: Alignment(0, 0),
    child: Container(
      width: 50,
      height: 50,
      decoration:
      BoxDecoration(color: item._color, shape: BoxShape.circle),
    ),
  ),
);

可以看到item 由中間向左平移

2020-05-21 23.03.35

如果我將item由(0,-1) 移動到(0,0), item位置同樣是(0,0), 應該會是這樣

item位置是定位的基準

2020-05-21 23.30.45 2020-05-21 23.34.54

如果item位置同樣是(0.5,0), 定位的十字會是這樣

image-20200521233825280

待續...

Last Updated: Thu May 21 2020 15:40:57 GMT+0000
贊助商連結
(adsbygoogle = window.adsbygoogle || []).push({});